// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2025 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
// Surface reconstruction from SPH particle positions.
// Uses the splashsurf tool from:
// https://github.com/InteractiveComputerGraphics/splashsurf
// =============================================================================

#ifndef CH_FSI_SPLASHSURF_SPH_H
#define CH_FSI_SPLASHSURF_SPH_H

#include <string>

#include "chrono_fsi/ChApiFsi.h"
#include "chrono_fsi/sph/ChFsiConfigSPH.h"
#include "chrono_fsi/sph/ChFsiFluidSystemSPH.h"

namespace chrono {
namespace fsi {
namespace sph {

/// @addtogroup fsisph_utils
/// @{

/// Surface reconstruction for SPH particle data.
/// Uses the `splashsurf` tool from https://github.com/InteractiveComputerGraphics/splashsurf.
class CH_FSI_API ChFsiSplashsurfSPH {
  public:
    ChFsiSplashsurfSPH(const ChFsiFluidSystemSPH& sysSPH);
    ~ChFsiSplashsurfSPH() {}

    /// Set the particle radius.
    void SetParticleRadius(double radius) { m_radius = radius; }

    /// Set the smoothing length used for the SPH kernel (in multiplies of the particle radius).
    /// The kernel compact support radius will be twice the smoothing length.
    void SetSmoothingLength(double length) { m_smoothing_length = length; }

    /// Set the cube edge length used for marching cubes (in multiplies of the particle radius).
    /// This corresponds to the cell size of the implicit background grid.
    void SetCubeSize(double size) { m_cube_size = size; }

    /// Set the iso-surface threshold for the density  (in multiplies of the rest density).
    /// This is the normalized value of the reconstructed density level that indicates the fluid surface.
    void SetSurfaceThreshold(double threshold) { m_surface_threshold = threshold; }

    /// Add arbitrary `splashsurf` arguments to the command.
    void AddArguments(const std::string& args) { m_arguments = args; }

    /// Save the current SPH particles to a JSON data file.
    void WriteParticleFileJSON(const std::string& filename);

    /// Run `splashsurf` for the specified input file.
    /// The input file (in_filename) must be a JSON file containing particle position information (as generated by
    /// WriteParticleFileJSON). The reconstructed surface will be written in the output file (out_filename). Supported
    /// output formats are: VTK, PLY, OBJ. If quiet=true, splashsurf console output is supressed.
    void WriteReconstructedSurface(const std::string& in_filename, const std::string& out_filename, bool quiet = false);

  private:
    const ChFsiFluidSystemSPH& m_sysSPH;
    double m_radius;
    double m_smoothing_length;
    double m_cube_size;
    double m_surface_threshold;

    std::string m_arguments;
};

/// @} fsisph_utils

}  // end namespace sph
}  // end namespace fsi
}  // end namespace chrono

#endif
